/*
 * AudioMediaSubsession.cpp
 *
 *  Created on: 2015年11月27日
 *      Author: terry
 */

#include "AudioMediaSubsession.h"
#include "AudioFramedSource.h"
#include "MPEG4GenericRTPSink.hh"
#include "AacHelper.h"
#include "TStringUtil.h"
#include "SimpleRTPSink.hh"
#include "CasterChannelTable.h"
#include "RtspConfig.h"


namespace av
{

AudioMediaSubsession::AudioMediaSubsession(UsageEnvironment& env, portNumBits initPort, MediaSourcePtr mediaSource, const std::string& entry):
		OnDemandServerMediaSubsession(env, false, initPort),
		m_mediaSource(mediaSource),
		m_entry(entry)
{
	m_mediaSource->getMediaFormat(m_mediaFormat);
}

AudioMediaSubsession::~AudioMediaSubsession()
{
}

#pragma warning(disable:4996)

char const* AudioMediaSubsession::sdpLines()
{
	if (fSDPLines != NULL)
	{
		return fSDPLines;
	}

	//return OnDemandServerMediaSubsession::sdpLines();

	MediaFormat& fmt = m_mediaFormat;

	unsigned estBitrate = fmt.m_channels * fmt.m_sampleRate * 2;
	char const* mediaType = "audio";
	unsigned char rtpPayloadType = 0;
	AddressString ipAddressStr(fServerAddressForSDP);
	std::string rtpmap;

	if (fmt.m_audioCodec == MEDIA_CODEC_AAC)
	{
		rtpPayloadType = 97;
		rtpmap = comn::StringUtil::format("a=rtpmap:%d MPEG4-GENERIC/%d/%d\r\n",
				rtpPayloadType, fmt.m_sampleRate, fmt.m_channels);
	}
	else if (fmt.m_audioCodec == MEDIA_CODEC_G711A)
	{
		rtpPayloadType = 8;
		rtpmap = comn::StringUtil::format("a=rtpmap:%d PCMA/%d/%d\r\n",
				rtpPayloadType, fmt.m_sampleRate, fmt.m_channels);
	}
	else if (fmt.m_audioCodec == MEDIA_CODEC_G711U)
	{
		rtpPayloadType = 0;
		rtpmap = comn::StringUtil::format("a=rtpmap:%d PCMU/%d/%d\r\n",
				rtpPayloadType, fmt.m_sampleRate, fmt.m_channels);
	}
    else if (fmt.m_audioCodec == MEDIA_CODEC_OPUS)
    {
        rtpPayloadType = 97;
        rtpmap = comn::StringUtil::format("a=rtpmap:%d OPUS/%d/%d\r\n",
            rtpPayloadType, fmt.m_sampleRate, fmt.m_channels);
    }

	char const* rtcpmuxLine = "";
	char const* rangeLine = rangeSDPLine();

    struct in_addr dummyAddr;
    dummyAddr.s_addr = 0;
	Groupsock* dummyGroupsock = createGroupsock(dummyAddr, 0);
	RTPSink* dummyRTPSink = createNewRTPSink(dummyGroupsock, rtpPayloadType, NULL);
    
	const char* tmpAux = dummyRTPSink->auxSDPLine();
    std::string auxSDPLine;
    if (tmpAux)
    {
        auxSDPLine = tmpAux;
    }

    Medium::close(dummyRTPSink);
    delete dummyGroupsock;

	char const* const sdpFmt =
		"m=%s %u RTP/AVP %d\r\n"
		"c=IN IP4 %s\r\n"
		"b=AS:%u\r\n"
		"%s"
		"%s"
		"%s"
		"%s"
		"a=control:%s\r\n";
	unsigned sdpFmtSize = strlen(sdpFmt)
		+ strlen(mediaType) + 5 /* max short len */ + 3 /* max char len */
		+ strlen(ipAddressStr.val())
		+ 20 /* max int len */
		+ rtpmap.size()
		+ strlen(rtcpmuxLine)
		+ strlen(rangeLine)
		+ strlen(auxSDPLine.c_str())
		+ strlen(trackId());
	char* sdpLines = new char[sdpFmtSize];
	sprintf(sdpLines, sdpFmt,
		mediaType, // m= <media>
		fPortNumForSDP, // m= <port>
		rtpPayloadType, // m= <fmt list>
		ipAddressStr.val(), // c= address
		estBitrate, // b=AS:<bandwidth>
		rtpmap.c_str(), // a=rtpmap:... (if present)
		rtcpmuxLine, // a=rtcp-mux:... (if present)
		rangeLine, // a=range:... (if present)
		auxSDPLine.c_str(), // optional extra SDP line
		trackId()); // a=control:<track-id>
	delete[] (char*)rangeLine;

	fSDPLines = strDup(sdpLines);
	delete[] sdpLines;

	return fSDPLines;
}

FramedSource* AudioMediaSubsession::createNewStreamSource(unsigned clientSessionId,
			          unsigned& estBitrate)
{
    MediaSourcePtr mediaSource = CasterChannelTable::instance().findWithName(m_entry);
	if (!mediaSource)
	{
		mediaSource = m_mediaSource;
	}

	MediaFormat fmt;
	mediaSource->getMediaFormat(fmt);

	estBitrate = fmt.m_audioBitrate / 1000;

	AudioFramedSource* pSource = new AudioFramedSource(envir(), mediaSource, m_mediaFormat.m_audioRate);

    return pSource;   
}

class PcmRtpSink : public SimpleRTPSink
{
public:
    PcmRtpSink(UsageEnvironment& env, Groupsock* RTPgs,
        unsigned char rtpPayloadFormat,
        unsigned rtpTimestampFrequency,
        char const* sdpMediaTypeString,
        char const* rtpPayloadFormatName,
        unsigned numChannels = 1,
        Boolean allowMultipleFramesPerPacket = True):
    SimpleRTPSink(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, sdpMediaTypeString,
        rtpPayloadFormatName, numChannels, false, true)
    {

    }

    virtual void doSpecialFrameHandling(unsigned fragmentationOffset,
        unsigned char* frameStart,
        unsigned numBytesInFrame,
    struct timeval framePresentationTime,
        unsigned numRemainingBytes)
    {
        setMarkerBit();

        MultiFramedRTPSink::doSpecialFrameHandling(fragmentationOffset,
            frameStart, numBytesInFrame,
            framePresentationTime,
            numRemainingBytes);
    }
};

  // "estBitrate" is the stream's estimated bitrate, in kbps
RTPSink* AudioMediaSubsession::createNewRTPSink(Groupsock* rtpGroupsock,
		        unsigned char rtpPayloadTypeIfDynamic,
		        FramedSource* inputSource)
{
	OutPacketBuffer::increaseMaxSizeTo(RtspConfig::packetBufferSize/2);

    MediaFormat& fmt = m_mediaFormat;

    RTPSink* pSink = NULL;

    if (fmt.m_audioCodec == MEDIA_CODEC_AAC)
    {
		std::string config = AacHelper::makeConfig(fmt.m_audioProfile,
			fmt.m_sampleRate, fmt.m_channels);

		pSink = MPEG4GenericRTPSink::createNew(envir(), rtpGroupsock,
			rtpPayloadTypeIfDynamic,
			fmt.m_sampleRate,
			"audio", "AAC-hbr", config.c_str(),
			fmt.m_channels);
    }
    else if (fmt.m_audioCodec == MEDIA_CODEC_G711A)
    {
        pSink = new PcmRtpSink(envir(), rtpGroupsock,
    				    8, fmt.m_sampleRate,
    				    "audio", "PCMA", fmt.m_channels, false);
    }
    else if (fmt.m_audioCodec == MEDIA_CODEC_G711U)
    {
        pSink =new PcmRtpSink(envir(), rtpGroupsock,
    				    0, fmt.m_sampleRate,
    				    "audio", "PCMU", fmt.m_channels, false);
    }
    else if (fmt.m_audioCodec == MEDIA_CODEC_OPUS)
    {
        pSink = new PcmRtpSink(envir(), rtpGroupsock,
            97, fmt.m_sampleRate,
            "audio", "OPUS", fmt.m_channels, false);
    }

    //pSink->enableRTCPReports() = false;

    return pSink;
}




} /* namespace av */
